//
// json_utils.cpp -- Implements utility functions for handling JSON data, including listing, finding, updating packages, reading configuration, and setting mirror URL.
//

#include "json_utils.h"
#include "tinybpt.h"
#include "utils.h"
#include <ctime>
#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>

void list_packages(const std::string &option) {
    if (option == "-all") {
        read_package_info(db_file, "packages");
    } else if (option == "-installed") {
        read_package_info(db_file, "localpackages");
    } else {
        std::cerr << "Invalid option: " << option << std::endl;
        return;
    }
    std::cout << "Package list:" << std::endl;
    for (const auto &pkg : packages) {
        std::cout << " - " << pkg.name << " (" << pkg.version << ")" << std::endl;
    }
}

void find_package(const std::string &name, const std::string &key) {
    read_package_info(db_file, key);
    for (const auto &pkg : packages) {
        if (pkg.name != name)
            continue;
        std::cout << "Found package: " << pkg.name << " (" << pkg.version << ")" << std::endl;
        std::cout << "Info: " << pkg.info << std::endl;
        std::cout << "Dependencies: " << pkg.dependencies << std::endl;
        return;
    }
    std::cout << "Package not found: " << name << std::endl;
}

void update_local_package_info(const std::string &json_file, const Package &pkg) {
    std::ifstream file(json_file);
    if (!file.is_open()) {
        std::cerr << "Failed to open file " << json_file << std::endl;
        return;
    }
    nlohmann::json json_data;
    try {
        file >> json_data;
    } catch (const nlohmann::json::parse_error &e) {
        std::cerr << "Failed to parse JSON file: " << e.what() << std::endl;
        file.close();
        return;
    }
    file.close();

    try {
        nlohmann::json new_package = {
            {"name", pkg.name},
            {"version", pkg.version},
            {"info", pkg.info},
            {"download_time", get_current_time()},
            {"dependencies", pkg.dependencies}
        };
        json_data["localpackages"].push_back(new_package);
        std::ofstream out_file(json_file);
        if (!out_file.is_open()) {
            std::cerr << "Failed to open file " << json_file << std::endl;
            return;
        }
        out_file << json_data.dump(4);
        out_file.close();
    } catch (const nlohmann::json::exception &e) {
        std::cerr << "Failed to update JSON data: " << e.what() << std::endl;
    }
}

void read_package_info(const std::string &json_file, const std::string &key) {
    packages.clear();
    std::ifstream file(json_file);
    if (!file.is_open()) {
        std::cerr << "Failed to open file " << json_file << std::endl;
        return;
    }
    nlohmann::json json_data;
    file >> json_data;
    file.close();
    try {
        for (const auto &package_json : json_data[key]) {
            Package pkg;
            pkg.name = package_json.at("name").get<std::string>();
            pkg.version = package_json.at("version").get<std::string>();
            pkg.info = package_json.at("info").get<std::string>();
            pkg.download_time = package_json.at("download_time").get<std::string>();
            pkg.dependencies = package_json.at("dependencies").get<std::string>();
            packages.push_back(pkg);
        }
    } catch (const nlohmann::json::exception &e) {
        std::cerr << "Failed to parse JSON file: " << e.what() << std::endl;
    }
}

Config read_config(const std::string &file_path) {
    std::ifstream file(file_path);
    if (!file.is_open()) {
        throw std::runtime_error("Failed to open config file");
    }
    nlohmann::json json_data;
    file >> json_data;
    file.close();
    Config config;
    config.mirror_url = json_data.at("config").at("mirror_url").get<std::string>();
    config.version = json_data.at("config").at("version").get<std::string>();
    config.target = json_data.at("config").at("target").get<std::string>();
    config.arch = json_data.at("config").at("arch").get<std::string>();
    config.buildroot_version = json_data.at("config").at("buildroot_version").get<std::string>();
    config.dirs = json_data.at("config").at("dirs").get<std::string>();
    return config;
}

void set_mirror_url(const std::string &new_mirror_url, const std::string &config_file) {
    std::ifstream file_in(config_file);
    nlohmann::json json_data;
    if (file_in.is_open()) {
        file_in >> json_data;
        file_in.close();
    } else {
        std::cout << "Unable to read config file\n";
        return;
    }
    json_data["config"]["mirror_url"] = new_mirror_url;
    std::ofstream file_out(config_file);
    if (file_out.is_open()) {
        file_out << json_data.dump(4);
        file_out.close();
        std::cout << "Mirror URL updated to: " << new_mirror_url << "\n";
    } else {
        std::cout << "Unable to write to config file\n";
    }
}

void show_mirror_url(const std::string &config_file) {
    Config config = read_config(config_file);
    std::cout << "Current Mirror URL: " << config.mirror_url << "\n";
}

void show_version(const std::string &config_file) {
    Config config = read_config(config_file);
    std::cout << "Tinybpt Version: " << config.version << "\n";
}